#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
#include <assert.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

using namespace std;

// 全局buffer无法进行通信：有写时拷贝的存在 无法更改通信

int main()
{
    // 1. 创建管道 0子进程读 1父进程写
    int pipefd[2] = {0}; // pipefd[0]: 读端 pipefd[1]: 写端
    int n = pipe(pipefd);

    assert(n != -1);
    (void)n; // assert只在断言下生效 在release下无用 若注释该行代码 release下会报错

#ifdef DEBUG
    cout << "pipefd[0]: " << pipefd[0] << endl; // 3
    cout << "pipefd[1]: " << pipefd[1] << endl; // 4
#endif

    // 2. 创建子进程
    pid_t id = fork();
    assert(id != -1);

    if (id == 0)
    {
        // 3.1 构建单向通信的信道 关闭子进程不需要的fd
        close(pipefd[1]); // 子进程 - 读 关闭写端

        char receive_buffer[1024 * 8];
        while (true)
        {
            // sleep(20); debug: 父写的快 子读的慢 父写满了无法再写只有子读了之后才能继续写

            // 写端fd未关闭 有数据就读 没数据就等
            // 写端fd关闭 读端 read返回0 ==> 读到了文件的结尾

            // ssize_t read(int fd, void *buf, size_t count);
            ssize_t s = read(pipefd[0], receive_buffer, sizeof(receive_buffer) - 1);
            if (s > 0)
            {
                receive_buffer[s] = 0; // 字符串自定义约定
                cout << "child[" << getpid() << "] get a message: Father[" << getppid() << "]# " << receive_buffer << endl;
            }
            else if (s == 0)
            {
                cout << "child: father(writer) exit, me(reader) quit!" << endl
                     << endl;
                break;
            }
        }
        // close(pipefd[0]); 进程退出 fd自动被关掉
        exit(0);
    }
    // 3.1 构建单向通信的信道 关闭父进程不需要的fd
    close(pipefd[0]); // 父进程 - 写 关闭读端

    string message = "Father is sending messages";
    int count = 0;
    char send_buffer[1024 * 8];
    while (true)
    {
        // 3.2 构建一个变化的字符串
        // int snprintf(char *str, size_t size, const char *format, ...);
        snprintf(send_buffer, sizeof(send_buffer), "%s: %d", message.c_str(), count++);
        // 3.3 写入
        // ssize_t write(int fd, const void *buf, size_t count);
        write(pipefd[1], send_buffer, strlen(send_buffer)); // 文件无需遵守Cstr的规定 不用将\0传入
        sleep(1);

        cout << count << endl;
        if (count == 5)
        {
            cout << endl
                 << "father: me(writer) quit!" << endl
                 << endl;
            break;
        }
    }
    close(pipefd[1]);

    // pid_t waitpid(pid_t pid, int *status, int options);
    pid_t ret = waitpid(id, nullptr, 0);
    cout << "child_id : " << id << " waitpid(): " << ret << endl;

    assert(ret > 0);
    (void)ret;

    return 0;
}
